package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import com.sky.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
public class AutoAspect {
    @Pointcut("execution(* com.sky.mapper.*.*(..))&&@annotation(com.sky.annotation.AutoFill)")
    public void AutoPointCut() {
    }

    @Before("AutoPointCut()")
    public void AutoFill(JoinPoint joinPoint) {

        //第1步 获得被切入点切入的方法上的注解 并且获得它里面的属性
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
        OperationType value = annotation.value();


        //第2步 获得方法参数中的实体类(自动填充的要求如果有多个参数第一个放的必须是实体类)
        Object[] args = joinPoint.getArgs();
        Object arg = args[0];

        //第3步 将需要赋值的值对象创建出来
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();

        //第4步 通过属性判断是什么方法
        try {
            if (value == OperationType.INSERT) {

                //第5步 通过实体类反射获得该类中的方法需要传入方法名以及方法参数的类型的字节码文件(这里就需要set的方法)
                Method setCreateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);


                //第6步 使用方法通过invoke(实体类对象,和值)来赋值
                setCreateTime.invoke(arg, now);
                setCreateUser.invoke(arg, id);
                setUpdateTime.invoke(arg, now);
                setUpdateUser.invoke(arg, id);

            } else if (value == OperationType.UPDATE) {
                Method setUpdateTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                setUpdateTime.invoke(arg, now);
                setUpdateUser.invoke(arg, id);
            }

        } catch (Exception ex) {
           throw new BaseException(MessageConstant.AUTOFILL_FAILED);
        }

    }

}
